// s.r(t), s.d(t, { default: () => ModelMeshModule })
import Module from "./Module"
import SymbolList from "../SymbolList"
import ApplicationData from "../data/ApplicationData"
import Vectors from "../three/Vectors"
import CameraData from "../data/CameraData"

import { InteractionModeChangeMessage } from "../message/inter.message"
import ModelDataModule from "./ModelDataModule"
import ModelData from "../data/ModelData"
import RaycasterModule from "./RaycasterModule"
import RenderToTextureModule from "./RenderToTextureModule"
import SweepData from "../data/SweepData"
import MeshTrimData from "../data/MeshTrimData"
import { PanoRenderTargetResizedMessage } from "../message/pano.message"
import { TourStartedMessage, TourStoppedMessage } from "../message/tour.message"
import { BeginSwitchViewmodeMessage, EndSwitchViewmodeMessage } from "../message/viewmode.message"
import ViewmodeData from "../data/ViewmodeData"
import O from "../math/79437"
import * as THREE from "three"
import MeshUtil from "../utils/MeshUtil"

import { ToggleMeshOverlayColorCommand } from "../command/mesh.command"
import { MeshPreviewSetPositonCommand } from "../command/mesh.command"
import MeshData from "../data/MeshData"
import { isPanOrMesh } from "../utils/viewmode.util"
let I = !1
const U = {
  meshTrimPositions: [],
  meshTrimScales: [],
  meshTrimsEnabled: []
}
function E() {
  return Object.assign({}, U)
}
class MeshTrimUniforms {
  floorUniforms: {}
  constructor() {
    this.floorUniforms = {}
  }
  setMeshTrim(e) {
    const { enabled: t, floorIndex: s, index: r, position: i, scale: a } = e,
      o = E()
    return (
      (o.meshTrimPositions = this.setMeshTrimPosition(s, r, i)),
      (o.meshTrimScales = this.setMeshTrimScale(s, r, a)),
      (o.meshTrimsEnabled = this.setMeshTrimEnabled(s, r, t)),
      (this.floorUniforms[s] = o),
      o
    )
  }
  updateMeshTrimArrays(e, t) {
    const s = E(),
      r = this.getFloorUniforms(e).meshTrimPositions.slice(),
      i = this.getFloorUniforms(e).meshTrimScales.slice(),
      a = this.getFloorUniforms(e).meshTrimsEnabled.slice()
    for (let e = 0; e < t.length; e++) {
      const s = !(e >= t.length) && t[e].enabled
      ;(r[e] = t[e].position), (i[e] = t[e].scale), a.push(s)
    }
    for (let e = t.length; e < meshTrimsLength; e++) (r[e] = new THREE.Vector3()), (i[e] = new THREE.Vector3()), a.push(!1)
    return (s.meshTrimPositions = r), (s.meshTrimScales = i), (s.meshTrimsEnabled = a), (this.floorUniforms[e] = s), s
  }
  setMeshTrimPosition(e, t, s) {
    const r = this.getFloorUniforms(e).meshTrimPositions.slice()
    return (r[t] = s), r
  }
  setMeshTrimScale(e, t, s) {
    const r = this.getFloorUniforms(e).meshTrimScales.slice()
    return (r[t] = s), r
  }
  setMeshTrimEnabled(e, t, s) {
    const r = this.getFloorUniforms(e).meshTrimsEnabled.slice()
    return (r[t] = s), r
  }
  getFloorUniforms(e) {
    return this.floorUniforms[`${e}`] || E()
  }
}
class MeshOverlayColor {
  getChunks: any
  TOOL_MESH_COLOR_OVERLAY: THREE.Vector4
  enabled: any
  toggleEnabled: (e: any) => void
  constructor(e) {
    ;(this.getChunks = e),
      (this.TOOL_MESH_COLOR_OVERLAY = new THREE.Vector4(0, 0, 0, 0.3)),
      (this.enabled = null),
      (this.toggleEnabled = e => {
        if (e !== this.enabled) {
          for (const t of this.getChunks()) t.setColorOverlay(e ? this.TOOL_MESH_COLOR_OVERLAY : null)
          this.enabled = e
        }
      })
  }
}
import funcUtil from "../utils/func.util"
import V from "../math/55356"
import Logger from "../utils/Logger"
import SettingsData from "../data/SettingsData"
import SettingsModule from "./SettingsModule"
import renderType from "../enum/renderType.enum"
import Chunk from "../other/321-8511"
import { SetMeshOverlayCommand } from "../command/mesh.command"
import { SetChunkRenderModeCommand } from "../command/render.command"
import { SetPanoOverlayCommand } from "../command/pano.command"
import FallbackMesh from "../mesh/FallbackMesh"
const re = new Logger("modelrenderer")
class ModelRenderer {
  scene: any
  container: any
  mesh: any
  panoRenderer: any
  meshData: any
  sweepData: any
  applicationData: any
  renderOptions: any
  chunkRenderingModeOverride: any
  lastChunkRenderingModeOverride: any
  fallbackMesh: FallbackMesh
  overlayTextures: { sweepId: any; texture: any; renderTarget: THREE.WebGLCubeRenderTarget; quaternion: THREE.Quaternion }[]
  overlayEnabled: boolean
  bindings: any[]
  updateFallbackMesh: () => void
  viewmodeData: any
  cameraData: any
  debugColorizeChunks: (t: any, s?: any) => void
  engine: any
  settings: any
  renderer: any
  currentSweepId: any
  targetSweepId: any
  lastViewmode: any
  constructor(e, t, s, r, i, a, o, n) {
    ;(this.scene = e),
      (this.container = t),
      (this.mesh = s),
      (this.panoRenderer = r),
      (this.meshData = i),
      (this.sweepData = a),
      (this.applicationData = o),
      (this.renderOptions = n),
      (this.chunkRenderingModeOverride = null),
      (this.lastChunkRenderingModeOverride = null),
      (this.fallbackMesh = new FallbackMesh()),
      (this.overlayTextures = [
        {
          sweepId: void 0,
          texture: void 0,
          renderTarget: new THREE.WebGLCubeRenderTarget(2048, {
            format: THREE.RGBAFormat
          }),
          quaternion: new THREE.Quaternion()
        },
        {
          sweepId: void 0,
          texture: void 0,
          renderTarget: new THREE.WebGLCubeRenderTarget(2048, {
            format: THREE.RGBAFormat
          }),
          quaternion: new THREE.Quaternion()
        }
      ]),
      (this.overlayEnabled = !1),
      (this.bindings = []),
      (this.updateFallbackMesh = (() => {
        const e = new THREE.Box3()
        return () => {
          if (this.sweepData.currentAlignedSweepObject && this.viewmodeData.isInside()) {
            const t = e.copy(this.meshData.bounds).expandByScalar(0.2)
            this.fallbackMesh.setBounds(t)
          } else this.cameraData && this.fallbackMesh.setFromCenterAndSize(this.cameraData.pose.position)
        }
      })()),
      (this.debugColorizeChunks = (() => {
        let e = !1
        return (t, s) => {
          const r = new THREE.Vector4(1, 1, 1, 0)
          ;(e = !e),
            (e => {
              for (const t of this.mesh.chunks) {
                const i = s ? 100 * t.id : 100 * t.meshSubgroup,
                  a = e ? V.G1(0.5, i) : r
                t.setColorOverlay(a)
              }
            })(t || e)
        }
      })())
  }
  init() {}
  dispose() {}
  async activate(e) {
    ;(this.engine = e),
      ([this.viewmodeData, this.settings, this.cameraData, this.renderer] = await Promise.all([
        e.market.waitForData(ViewmodeData),
        e.market.waitForData(SettingsData),
        e.market.waitForData(CameraData),
        e.getModuleBySymbol(SymbolList.WEBGL_RENDERER)
      ])),
      this.scene.add(this.container),
      this.scene.add(this.fallbackMesh),
      (this.fallbackMesh.layers.mask = this.container.layers.mask),
      this.updateRenderState(),
      this.bindings.push(
        this.viewmodeData.onChanged(this.updateRenderState.bind(this)),
        this.sweepData.onChanged(this.updateRenderState.bind(this)),
        this.settings.onChanged(this.updateRenderState.bind(this)),
        e.commandBinder.addBinding(SetMeshOverlayCommand, this.onMeshOverlayCommand),
        e.commandBinder.addBinding(SetChunkRenderModeCommand, this.onSetChunkRenderStateCommand),
        e.commandBinder.addBinding(SetPanoOverlayCommand, this.onPanoOverlayCommand)
      ),
      this.renderOptions.colorizeRooms && this.debugColorizeChunks(!0),
      this.renderOptions.colorizeChunks && this.debugColorizeChunks(!0, !0),
      this.renderOptions.wireframe && this.toggleWireframe(!0)
  }
  deactivate() {
    for (const e of this.bindings) e.cancel()
    ;(this.bindings = []),
      this.scene.remove(this.container),
      this.scene.remove(this.fallbackMesh),
      this.currentSweepId && this.panoRenderer.freeTexture(this.currentSweepId),
      (this.currentSweepId = null),
      (this.targetSweepId = null)
  }
  updateSweepRenderTarget(e, t, s, r) {
    const i = this.panoRenderer.useTexture(t)
    if (i) for (const t of this.allChunks()) t.setProjectedPano(e, s, r, i)
  }
  *allChunks() {
    yield* this.mesh.chunks, yield this.fallbackMesh.chunk
  }
  updateExistingTexture(e, t, s?, r?) {
    for (const i of this.allChunks()) e === this.currentSweepId && i.setProjectedPano(0, s, r, t), e === this.targetSweepId && i.setProjectedPano(1, s, r, t)
  }
  render() {}
  beforeRender() {
    const e = !this.displayingUnaligned(this.sweepData, this.viewmodeData)
    this.container.visible = e
    const { floorOpacity: t, roomFadeDist: s } = this.meshData.meshGroupVisuals
    for (const e of this.mesh.chunks) {
      const r = t.get(e.meshGroup) || 0
      let i = funcUtil.focalDistance(e.material.opacity, r, 0.2)
      Math.abs(i - r) < 1e-4 && (i = r),
        e.setMaterialsUniform({
          meshOpacity: this.meshData.meshTextureOpacity.value,
          panoOpacity: 1 - this.meshData.meshTextureOpacity.value,
          opacity: i,
          transparentDiscardDist: s.get(e.meshGroup, e.meshSubgroup) || 0,
          progress: this.sweepData.transition.progress.value
        })
    }
    const r = O.w2(this.meshData.meshTextureOpacity.value, 0, 1, 1)
    this.fallbackMesh.chunk.setMeshTextureOpacity(r), this.fallbackMesh.chunk.setProgress(this.sweepData.transition.progress.value), this.updateFallbackMesh()
  }
  displayingUnaligned(e, t) {
    return t.closestMode === viewmodeEnum.Panorama && !!e.currentSweep && e.isSweepUnaligned(e.currentSweep)
  }
  updateChunkMaterialMode(e, t) {
    const s = t || renderType.Standard,
      r = e ? THREE.DoubleSide : THREE.FrontSide
    for (const e of this.mesh.chunks) e.setRenderingMode(s), e.setSide(r)
  }
  updateRenderState() {
    if (
      ((this.container.visible = this.settings.tryGetProperty(configConst.meshKey, !0)),
      this.viewmodeData.currentMode !== this.lastViewmode || this.lastChunkRenderingModeOverride !== this.chunkRenderingModeOverride)
    ) {
      this.lastChunkRenderingModeOverride = this.chunkRenderingModeOverride
      const e = this.viewmodeData.isInside()
      this.updateChunkMaterialMode(e, this.chunkRenderingModeOverride), (this.lastViewmode = this.viewmodeData.currentMode)
    }
    if ((this.viewmodeData.transition.active && isPanOrMesh(this.viewmodeData.transition.to)) || this.viewmodeData.isInside()) {
      const e = this.sweepData.currentSweep,
        t = this.sweepData.transition,
        s = t.active && (this.applicationData.phase === phaseMin.PLAYING || this.applicationData.phase === phaseMin.STARTING),
        r = s ? t.from : e,
        i = s ? t.to : e,
        a = this.currentSweepId,
        o = this.targetSweepId
      ;(this.currentSweepId = r || null),
        (this.targetSweepId = i || null),
        this.handleSweepChange(0, a, this.currentSweepId),
        this.handleSweepChange(1, o, this.targetSweepId)
    }
    if (this.overlayEnabled) {
      const e = this.overlayTextures.find(e => e.sweepId === this.currentSweepId),
        t = this.overlayTextures.find(e => e.sweepId === this.targetSweepId)
      for (const s of this.allChunks())
        s.setOverlayPano(0, e ? e.quaternion : void 0, e ? e.texture : void 0), s.setOverlayPano(1, t ? t.quaternion : void 0, t ? t.texture : void 0)
    }
  }
  handleSweepChange(e, t, s) {
    if (t !== s && (t && this.panoRenderer.freeTexture(t), s)) {
      const t = this.sweepData.getSweep(s)
      this.updateSweepRenderTarget(e, s, t.position, t.rotation)
    }
  }
  async onPanoOverlayCommand(e) {
    this.overlayEnabled = !0
    const t = t => {
      const s = t.renderTarget
      ;(t.renderTarget.width = e.texture.image.width),
        (t.renderTarget.height = e.texture.image.height),
        (t.sweepId = e.sweepId),
        (t.texture = s.texture),
        (t.quaternion = e.quaternion),
        this.renderer.cwfRenderer.copyCubemap(e.texture, t.renderTarget)
    }
    let s = !1
    for (const r of this.overlayTextures) s || r.sweepId !== e.sweepId || (t(r), (s = !0))
    for (const e of this.overlayTextures) s || e.sweepId === this.targetSweepId || e.sweepId === this.currentSweepId || (t(e), (s = !0))
    this.updateRenderState()
  }
  async onMeshOverlayCommand(e) {
    const t = this.meshData.meshGroups.rooms,
      s = this.meshData.meshGroups.roomIds,
      r = this.meshData.meshGroups.floors,
      i = this.meshData.meshGroups.floorIds
    let a
    switch (e.selectBy) {
      case SetMeshOverlayCommand.selectBy.all:
        a = () => !0
        break
      case SetMeshOverlayCommand.selectBy.byFloorId:
        a = t => {
          let s = !1
          for (const a of r) t.meshGroup === a.meshGroup && i[t.meshGroup] === e.id && (s = !0)
          return s
        }
        break
      case SetMeshOverlayCommand.selectBy.byRoomId:
        a = r => {
          let i = !1
          for (const { meshSubgroup: a, meshGroup: o } of t)
            r.meshSubgroup === a && r.meshGroup === o && s.get(r.meshGroup, r.meshSubgroup) === e.id && (i = !0)
          return i
        }
        break
      case SetMeshOverlayCommand.selectBy.byMeshGroup:
        a = t => t.meshGroup === e.index
        break
      case SetMeshOverlayCommand.selectBy.byMeshSubGroup:
        a = t => t.meshSubgroup === e.index
    }
    if (!a) return
    let o: any = "rand"
    e.colorStyle === SetMeshOverlayCommand.colorBy.explicit && (o = e.color ? new THREE.Vector4(e.color.x, e.color.y, e.color.z, e.color.w) : null)
    for (const t of this.mesh.chunks) a(t) && t.setColorOverlay("rand" === o ? V.G1(e.alpha) : o)
  }
  async onSetChunkRenderStateCommand(e) {
    ;(this.chunkRenderingModeOverride = e.mode), this.updateRenderState()
  }
  toggleWireframe(e) {
    for (const t of this.mesh.chunks) t.setWireframe(e)
  }
  async debugCycleChunkMaterials() {
    const e = []
    for (const t in meshEnum) isNaN(Number(t)) && e.push(meshEnum[t])
    const t = []
    for (const e in renderType) isNaN(Number(e)) && t.push(renderType[e])
    re.info(`Available ChunkMaterialCapabilities: ${e}`)
    const s = []
    for (let t = 0; t < 1 << (e.length - 1); t++) {
      const r = {}
      for (let s = e.length - 1; s >= 0; s--) {
        r[e[s]] = Boolean(t & (1 << s))
      }
      s.push(r)
    }
    re.info(`There are ${s.length * t.length} options to test`)
    for (let e = 0; e < t.length; e++) {
      await this.engine.commandBinder.issueCommand(new SetChunkRenderModeCommand(e))
      for (const t of s) {
        re.info(`Testing ChunkRenderingMode.${renderType[e]} with capabilities: ${JSON.stringify(t, void 0, 2)}`)
        const s = new THREE.Vector4(Math.random(), Math.random(), Math.random(), 0.5)
        for (const e of Object.keys(t))
          for (const r of this.mesh.chunks) r.setColorOverlay(s), r.setMeshPreviewSphere(new THREE.Vector3(0, 0, 0)), r.overrideCapability(e, t[e])
        await funcUtil.waitRun(100)
      }
      await funcUtil.waitRun(100)
    }
    await this.engine.commandBinder.issueCommand(new SetChunkRenderModeCommand(null))
  }
}
class MeshRenderPass {
  slots: any
  renderToTextureModule: any
  width: number
  height: number
  sizeMultiplier: number
  pixelBuffer: Uint8Array
  readBuffer: any
  readPixelsAsync: Promise<any>
  _renderTarget: THREE.WebGLRenderTarget
  constructor(e, t, s = 128, r = 128) {
    ;(this.slots = e),
      (this.renderToTextureModule = t),
      (this.width = s),
      (this.height = r),
      (this.sizeMultiplier = 1 / 8),
      (this.pixelBuffer = new Uint8Array(4)),
      (this.readBuffer = null),
      (this.readPixelsAsync = Promise.resolve(this.pixelBuffer))
  }
  get renderTarget() {
    return (
      this._renderTarget ||
        (this._renderTarget = new THREE.WebGLRenderTarget(this.width, this.height, {
          type: THREE.UnsignedByteType,
          format: THREE.RGBAFormat,
          depthBuffer: !1,
          stencilBuffer: !1,
          generateMipmaps: !1,
          minFilter: THREE.NearestFilter,
          magFilter: THREE.NearestFilter
        })),
      this._renderTarget
    )
  }
  pixels() {
    return this.pixelBuffer
  }
  renderAndReadAsync(e, t) {
    this.beforeRender(),
      this.updateReadBufferSize(),
      (this.readPixelsAsync = this.renderToTextureModule
        .renderAndReadAsync(
          { mesh: e, camera: t, target: this.renderTarget, clear: !0 },
          { x: 0, y: 0, width: this.width, height: this.height },
          { buffer: this.pixelBuffer }
        )
        .then(e => ((this.pixelBuffer = e), this.pixelBuffer))),
      this.afterRender()
  }
  render(e, t, s = !1, r = !0) {
    this.beforeRender()
    let { width: i, height: a } = this.renderToTextureModule.getRenderSize()
    ;(i = Math.max(1, Math.floor(i * this.sizeMultiplier))),
      (a = Math.max(1, Math.floor(a * this.sizeMultiplier))),
      (i === this.renderTarget.width && a === this.renderTarget.height) || this.renderTarget.setSize(i, a),
      this.renderToTextureModule.render(this.renderTarget, e, t),
      s && this.renderToScreen(),
      r && this.afterRender()
  }
  renderToScreen() {
    this.renderToTextureModule.renderToScreen(this.renderTarget, !1)
  }
  readPixels() {
    this.updateReadBufferSize()
    const e = this.pixelBuffer
    return (this.pixelBuffer = this.renderToTextureModule.getRenderTargetData(this.renderTarget, e)), this.pixelBuffer
  }
  updateReadBufferSize() {
    const e = this.renderTarget.width * this.renderTarget.height * 4
    this.pixelBuffer.length !== e && (this.pixelBuffer = new Uint8Array(e))
  }
  beforeRender() {
    ;(this.width === this.renderTarget.width && this.height === this.renderTarget.height) || this.renderTarget.setSize(this.width, this.height)
    for (const e of this.slots) for (const t of e.chunks) this.beforeRenderChunk(t, e)
  }
  beforeRenderChunk(...e) {}
  afterRender() {
    for (const e of this.slots) for (const t of e.chunks) this.afterRenderChunk(t, e)
  }
  afterRenderChunk(...e) {}
}
class TextureQualityRenderPass extends MeshRenderPass {
  prevColor: WeakMap<object, any>
  constructor(a?, b?, c?, d?) {
    super(a, b, c, d)
    this.prevColor = new WeakMap()
  }
  beforeRenderChunk(e, t) {
    t.quality in t.config && (this.prevColor.set(t, e.getColorOverlay()), e.setColorOverlay(t.config[t.quality].debugColor))
  }
  afterRenderChunk(e, t) {
    var s
    e.setColorOverlay(null !== (s = this.prevColor.get(t)) && void 0 !== s ? s : null)
  }
}
class TextureScoreRenderPass extends MeshRenderPass {
  prevColor: WeakMap<object, any>
  maxValue: any
  constructor(a?, b?, c?, d?) {
    super(a, b, c, d)
    this.prevColor = new WeakMap()
  }
  beforeRender() {
    ;(this.maxValue = this.slots.reduce((e, t) => Math.max(e, t.screenCoverageScore), 1e-9)), super.beforeRender()
  }
  beforeRenderChunk(e, t) {
    const s = t.screenCoverageScore / this.maxValue,
      r = new THREE.Vector4(s, s, s, 1)
    this.prevColor.set(t, e.getColorOverlay()), e.setColorOverlay(r)
  }
  afterRenderChunk(e, t) {
    var s
    e.setColorOverlay(null !== (s = this.prevColor.get(t)) && void 0 !== s ? s : null)
  }
}
import chunkUtil from "../utils/chunk.util"
import CircularBuffer from "../three/CircularBuffer"
import lodEnum from "../enum/lod.enum"
class MeshTextureSlot {
  streamStyle: any
  lod: number
  chunks: Set<any>
  loading: boolean
  screenCoverage: number
  screenCoverageScore: number
  sightings: CircularBuffer
  textureName: any
  config: { [x: number]: { debugColor: THREE.Vector4; textureSize: number; tileSize: number; assetType: string; assetSize: number; texelSize: number } }
  minQuality: number
  quality: any
  maxQuality: any
  targetQuality: any
  texture: any
  textureData: any
  constructor(e, t, s = lodEnum.Standard, r) {
    this.streamStyle = t
    this.lod = s
    this.chunks = new Set()
    this.loading = !1
    this.screenCoverage = 0
    this.screenCoverageScore = 0
    this.sightings = new CircularBuffer(100)
    this.textureName = e
    this.streamStyle = t
    this.config = chunkUtil.getConfig(this.streamStyle)
    this.minQuality = chunkUtil.getMinQuality(this.streamStyle, s)
    r && (this.quality = r)
    this.minQuality = this.quality
    this.maxQuality = this.minQuality
    this.targetQuality = this.minQuality
  }
  setTexture(e) {
    this.texture && this.texture !== e && this.texture.dispose(), (this.texture = e)
    for (const e of this.chunks) e.setMeshTexture(this.texture)
  }
  async getUrl(e) {
    const t = this.config[e],
      { assetType: s } = t
    if (this.textureData) {
      const e = this.textureName.match(/[_.]([0-9]{3})[_.]/)
      if (!e) throw new Error(`Could not parse texture index from texture name: ${this.textureName}`)
      return (await this.textureData[s].get()).urlTemplate.replace("<texture>", e[1])
    }
    {
      if (this.streamStyle === chunkType.TILE) return `${configConst.tileSet}/textures_${s}/${this.textureName}.jpg`
      const e = this.textureName.match(/^([a-f0-9]+(_10k|_50k)?)/)
      // if (!e)
      //   throw new Error(`Unknown format for texture name: ${this.textureName}`)彭蔚

      return `_texture_jpg_high/${this.textureName}`
    }
  }
}
class TextureBudgeter {
  lods: Map<any, any>
  orders: {}
  qualMin: number
  qualMax: number
  streamStyle: any
  slots: any
  config: { [x: number]: { debugColor: THREE.Vector4; textureSize: number; tileSize: number; assetType: string; assetSize: number; texelSize: number } }
  baseSizeUnit: any
  maxBudget: number
  minBudget: any
  _budget: any
  constructor() {
    ;(this.lods = new Map()), (this.orders = {}), (this.qualMin = 1 / 0), (this.qualMax = -1 / 0)
  }
  updateBudgetForStyle(e, t) {
    ;(this.streamStyle = e),
      (this.slots = t),
      (this.config = chunkUtil.getConfig(this.streamStyle)),
      t.forEach(e => {
        const t = this.lods.get(e.lod) || new Set()
        t.add(e), this.lods.set(e.lod, t)
      })
    for (const [e] of this.lods.entries())
      (this.orders[e] = chunkUtil.getOrder(this.streamStyle, e)), (this.qualMin = Math.min(this.qualMin, chunkUtil.getMinQuality(this.streamStyle, e)))
    this.baseSizeUnit = this.config[this.qualMin].textureSize
    let s = 0
    for (const [e, t] of this.lods.entries()) {
      const r = chunkUtil.getMaxQuality(this.streamStyle, e)
      ;(s += t.size * this.getBudgetSize(r)), (this.qualMax = Math.max(this.qualMax, r))
    }
    return (this.maxBudget = s), (this.minBudget = this.slots.length), (this._budget = this.minBudget), this
  }
  update(e) {
    this.budget = this.maxBudget
  }
  getBudgetSize(e) {
    return e ? (this.config[e].textureSize / this.baseSizeUnit) ** 2 : 0
  }
  calcCurrentUsedBudget() {
    return this.slots.reduce((e, t) => e + this.getBudgetSize(t.quality), 0)
  }
  clampBudget(e) {
    return Math.min(this.maxBudget, Math.max(this.minBudget, e))
  }
  get budget() {
    return this._budget
  }
  set budget(e) {
    ;(e = this.clampBudget(e)), this.budget !== e && ((this._budget = e), this.updateTargetQualitiesFromBudget())
  }
  updateTargetQualitiesFromBudget() {
    let e = 0
    for (const t of this.slots) (t.targetQuality = t.minQuality), (e += this.getBudgetSize(t.targetQuality))
    for (const [t, s] of this.lods.entries())
      for (const r of this.orders[t])
        for (const t of s)
          if (!(t.maxQuality < r)) {
            if (((e -= this.getBudgetSize(t.targetQuality)), (e += this.getBudgetSize(r)), e > this.budget)) return
            t.targetQuality = r
          }
  }
}
import de from "../math/69626"
import { ScheduleTaskCommand } from "../command/task.command"
import RoomMesh from "../mesh/RoomMesh"
import pe from "../other/321-86980"
import { createSubscription } from "../utils/Subscription"
class ChunkVisibilityChecker {
  scene: any
  raycaster: any
  issueCommand: any
  chunkSightings: Map<any, any>
  raycastCounter: number
  onNewSighting: Set<Function>
  raycastRandomScreenLocation: (r: any, i: any, a: any) => void
  gatherTaskPromise: any
  camera: any
  constructor(e, t, s) {
    ;(this.scene = e),
      (this.raycaster = t),
      (this.issueCommand = s),
      (this.chunkSightings = new Map()),
      (this.raycastCounter = 0),
      (this.onNewSighting = new Set()),
      (this.raycastRandomScreenLocation = (() => {
        const e = new THREE.Vector3(),
          t = new THREE.Vector3(),
          s = new THREE.Vector3()
        return (r, i, a) => {
          this.raycastCounter++
          const o = (2 - 2 * i) / r,
            n = -1 + i,
            h = this.raycastCounter % (r * r),
            d = h % r,
            l = n + ((h - d) / r) * o,
            u = n + d * o + Math.random() * o,
            c = l + Math.random() * o
          e.set(u, c, -1).unproject(this.camera), t.set(u, c, 1).unproject(this.camera), s.subVectors(t, e).normalize()
          const m = this.raycaster.pick(e, s, funcUtil.raycastVisible)
          if (m) {
            if (m.face && m.object instanceof RoomMesh) {
              const e = m.object.getChunk(m.face.materialIndex),
                t = e.meshSubgroup,
                s = {
                  point: m.point.clone(),
                  raycastAge: this.raycastCounter
                }
              this.chunkSightings.set(t, s)
              for (const t of this.onNewSighting.values()) t(e, s)
            }
            a && a(m)
          }
        }
      })()),
      (this.camera = e.camera)
  }

  update() {
    if (!this.gatherTaskPromise) {
      const e = () => {
          const e = configConst.switchConfig.debugLOD ? pe.e(65280, this.scene) : void 0,
            t = performance.now()
          for (; performance.now() - t < 1.5; ) this.raycastRandomScreenLocation(5, 0.05, e)
        },
        t = async e => {
          await e.promise, (this.gatherTaskPromise = null)
        },
        s = new ScheduleTaskCommand("mesh/texture/raycast", e, 50)
      this.gatherTaskPromise = this.issueCommand(s).then(t)
    }
  }
  chunkVisible(e, t = 1e3) {
    const s = this.chunkSightings.get(e)
    return !!s && this.raycastCounter - s.raycastAge < t
  }
  notifyOnNewSighting(e) {
    return createSubscription(
      () => this.onNewSighting.add(e),
      () => this.onNewSighting.delete(e),
      !0
    )
  }
}
const ye = new Logger("tex-lod")
class MeshTextureLoader {
  uuid: any
  textureLOD: any
  urls: any
  modelObject: any
  camera: any
  cameraData: any
  renderer: any
  renderToTextureModule: any
  engine: any
  chunkVisibilityChecker: any
  name: string
  slots: any[]
  textureNameToSlot: {}
  chunkIdToSlot: any
  concurrentLoadingTextures: number
  concurrentDownloadingTiles: number
  autoLoadTiles: boolean
  lastSortedAt: number
  loadingTextures: number
  downloadingTiles: number
  totalTextures: {}
  totalTiles: number
  textureQualityRenderPass: TextureQualityRenderPass
  textureScoreRenderPass: TextureScoreRenderPass
  _chunkSlotsSet: Set<any>
  streamingStyle: any
  textures: any
  minQuality: number
  maxQuality: number
  textureBudgeter: TextureBudgeter
  analyzeTaskPromise: any
  constructor(e, t, s, r, i, a, o, n, h, uuid) {
    this.uuid = uuid
    this.textureLOD = e
    this.urls = t
    this.modelObject = s
    this.camera = r
    this.cameraData = i
    this.renderer = a
    this.renderToTextureModule = o
    this.engine = n
    this.chunkVisibilityChecker = h
    this.name = "texture-streaming"
    this.slots = []
    this.textureNameToSlot = {}
    this.chunkIdToSlot = {}
    this.concurrentLoadingTextures = 1
    this.concurrentDownloadingTiles = 12
    this.autoLoadTiles = !1
    this.lastSortedAt = 0
    this.loadingTextures = 0
    this.downloadingTiles = 0
    this.totalTextures = {}
    this.totalTiles = 0
    this.textureQualityRenderPass = new TextureQualityRenderPass(this.slots, this.renderToTextureModule)
    this.textureScoreRenderPass = new TextureScoreRenderPass(this.slots, this.renderToTextureModule)
    this._chunkSlotsSet = new Set()
  }
  setModel(e, t, s, r) {
    this.streamingStyle = e
    this.textures = r
    this.minQuality = chunkUtil.getMinQuality(this.streamingStyle)
    this.maxQuality = chunkUtil.getMaxQuality(this.streamingStyle)
    this.modelObject = t
    this.slots.length = 0
    this.textureNameToSlot = {}
    this.chunkIdToSlot = {}
    this.addChunkSlots([...s])
    this.textureBudgeter = new TextureBudgeter().updateBudgetForStyle(this.streamingStyle, this.slots)
    this.chunkVisibilityChecker.notifyOnNewSighting((e, t) => {
      const s = this.addChunkSlots([e])
      for (const e of s) e.sightings.push(t)
    })
  }
  addChunkSlots(e) {
    this._chunkSlotsSet.clear()
    let t = !1
    for (const s of e) {
      const e = s.textureName
      let r = this.textureNameToSlot[e]
      if (!r) {
        let i
        t = !0
        s.textureSizeEmbedded && (i = chunkUtil.canUseQuality(s.textureSizeEmbedded, this.streamingStyle, s.lod))
        r = new MeshTextureSlot(e, this.streamingStyle, s.lod, i)
        r.maxTextureAssetSize = s.textureSizeMax
        this.textures && (r.textureData = this.textures)
        this.textureNameToSlot[s.textureName] = r
        this.slots.push(r)
      }
      r.chunks.has(s) || ((t = !0), r.chunks.add(s)), this._chunkSlotsSet.add(r)
      this.chunkIdToSlot[s.id] = r
    }
    return t && this.textureBudgeter && this.textureBudgeter.updateBudgetForStyle(this.streamingStyle, this.slots), this._chunkSlotsSet
  }
  setQuality(e, t) {
    if (e > t) throw new Error("min quality must be smaller or equal to max")
    ;(this.minQuality = e), (this.maxQuality = t)
    for (const e of this.slots)
      (e.minQuality = Math.max(chunkUtil.getMinQuality(e.streamStyle, e.lod), this.minQuality)), (e.maxQuality = Math.min(e.maxQuality, this.maxQuality))
  }
  get textureCount() {
    return this.slots.length
  }
  loadAll(e) {
    if (!this.slots[0] || !this.slots[0].textureName) return Promise.resolve([])
    this.streamingStyle !== chunkType.DAM &&
      ye.error(`textureStreaming.loadAll(${chunkEnum[e]}) not supported with tiles, quality is different per lod`, this.slots)
    const t = this.slots.map(t => this.loadTexture(t, e, !1))
    return Promise.all(t)
  }
  async loadTexture(e, t, s = !0) {
    const r = chunkUtil.getConfig(this.streamingStyle)
    t in r || ye.warn(chunkEnum[t], "not found in", this.streamingStyle, r)
    const i = r[t],
      a = e.maxTextureAssetSize || i.assetSize,
      o = Math.min(a, i.textureSize)
    e.lastLoadedAt = performance.now()
    let n = e.texture
    if (n && t === e.quality) return ye.info(`Texture was already at level ${chunkEnum[t]}, not reloading`), e.texture
    if (n && t < e.quality) {
      const s = this.renderToTextureModule.resizeTexture(n, o)
      return (e.quality = t), e.setTexture(s), e.texture
    }
    ;(n = new THREE.Texture()),
      (n.format = THREE.RGBFormat),
      this.renderer.initSizedTexture2D(o, n),
      (e.loading = !0),
      this.loadingTextures++,
      (this.totalTextures[o] = (this.totalTextures[o] || 0) + 1)
    try {
      n.sourceFile = this.uuid + "_50k" + (await e.getUrl(t))
      this.textureLOD !== textureEnum.NONE && s ? await this.updateTextureTiled(n, t, e) : await this.updateTextureSolid(n, t)
      e.setTexture(n)
    } catch (e) {
      ye.warn(`Failed loading texture ${n.sourceFile}`, e)
    } finally {
      this.loadingTextures--, (e.quality = t), (e.loading = !1)
    }
    return n
  }
  async updateTextureTiled(e, t, s) {
    ;(e.generateMipmaps = !1), (e.minFilter = THREE.LinearFilter), (e.magFilter = THREE.LinearFilter)
    const r = chunkUtil.getConfig(this.streamingStyle),
      i = void 0 !== s.maxTextureAssetSize ? s.maxTextureAssetSize : r[t].assetSize,
      a = Math.min(i, r[t].textureSize),
      o = Math.min(a, r[t].tileSize),
      n = i / (a / o),
      h = async (t, s) => {
        const r: any = {}
        let h
        n !== o && (r.width = `${o}`), n !== i && (r.crop = `${n},${n},x${t / a},y${s / a}`), (this.downloadingTiles += 1), (this.totalTiles += 1)
        try {
          h = await this.urls.getImageBitmap(
            e.sourceFile,
            o,
            o,
            {
              priority: httpPriority.LOW,
              flipY: configConst.switchConfig.flipDownload
            },
            r
          )
        } finally {
          this.downloadingTiles -= 1
        }
        const d = t,
          l = configConst.switchConfig.flipUpload ? a - s - o : s,
          u = new ScheduleTaskCommand(
            "mesh/texture/upload-tiles",
            () =>
              this.engine.after(phaseState.End).then(() => {
                this.renderer.uploadTexture2D(h, e, d, l)
              }),
            100
          )
        return (await this.engine.commandBinder.issueCommand(u)).promise
      },
      d = []
    for (let e = 0; e < a; e += o) for (let t = 0; t < a; t += o) d.push(h(e, t))
    return Promise.all(d)
  }
  async updateTextureSolid(e, t) {
    const s = chunkUtil.getConfig(this.streamingStyle),
      { textureSize: r } = s[t],
      i = configConst.switchConfig.flipDownload,
      a = await this.urls.getImageBitmap(e.sourceFile, r, r, { priority: httpPriority.LOW, flipY: i }, { width: `${r}` })
    this.renderer.uploadTexture2D(a, e, 0, 0)
  }
  analyzeTextureScreenCoverageFromRaycasts() {
    const e = window.innerWidth,
      t = new THREE.Vector3().copy(this.cameraData.pose.position)
    for (const s of this.slots) {
      ;(s.screenCoverage = 0), (s.screenCoverageScore = 0), (s.maxQuality = s.minQuality)
      for (const r of s.sightings) {
        if (this.chunkVisibilityChecker.raycastCounter - r.raycastAge > 1e3) continue
        const i = t.distanceTo(r.point),
          a = de._U(i, this.camera.projectionMatrix, e)
        let o = chunkUtil.canUseQuality(a, this.streamingStyle, s.lod)
        ;(o = Math.min(o, this.maxQuality)), (s.screenCoverageScore += o), (s.screenCoverage += 1), (s.maxQuality = Math.max(o, s.maxQuality))
      }
    }
    this.slots.sort((e, t) => t.screenCoverageScore - e.screenCoverageScore), this.textureBudgeter.updateTargetQualitiesFromBudget()
  }
  update(e) {
    if ((this.textureBudgeter.update(e), !this.camera || !this.autoLoadTiles)) return
    const t = performance.now()
    this.textureLOD === textureEnum.RAYCAST && this.minQuality !== this.maxQuality && this.scheduleRaycastTasks(t)
    for (let e = this.slots.length - 1; e >= 0; e--) {
      const s = this.slots[e],
        r = funcUtil.getMax(s.targetQuality, s.minQuality, s.maxQuality),
        i = t - s.lastLoadedAt < 1e3
      if (!s.loading && s.quality > r && !i) {
        this.loadTexture(s, r)
        break
      }
    }
    for (const e of this.slots) {
      if (this.loadingTextures >= this.concurrentLoadingTextures || this.downloadingTiles >= this.concurrentDownloadingTiles) break
      const t = funcUtil.getMax(e.targetQuality, e.minQuality, e.maxQuality)
      !e.loading && e.quality < t && this.loadTexture(e, chunkUtil.canUseID(e.quality, this.streamingStyle, e.lod))
    }
    configConst.switchConfig.debugRttScores && this.textureScoreRenderPass.render(this.modelObject, this.camera, !0, configConst.switchConfig.debugRttClear),
      configConst.switchConfig.debugRttQuality &&
        this.textureQualityRenderPass.render(this.modelObject, this.camera, !0, configConst.switchConfig.debugRttClear)
  }
  scheduleRaycastTasks(e) {
    if (!this.analyzeTaskPromise && e - this.lastSortedAt > 200) {
      const e = () => {
          this.analyzeTextureScreenCoverageFromRaycasts(), (this.lastSortedAt = performance.now())
        },
        t = async e => {
          await e.promise, (this.analyzeTaskPromise = null)
        },
        s = new ScheduleTaskCommand("mesh/texture/analyze-screen-coverage", e, 100)
      this.analyzeTaskPromise = this.engine.commandBinder.issueCommand(s).then(t)
    }
  }
}
import RoomMeshData from "../data/RoomMeshData"
import ModelMeshTiled from "../mesh/ModelMeshTiled"
import ModelMeshDam from "../mesh/ModelMeshDam"
import configConst from "../constant/config.const"
import { phaseMin, phaseState } from "../enum/phase.enum"
import { deviceList } from "../enum/interactive.enum"
import meshEnum from "../enum/mesh.enum"
import { BeginMoveToSweepMessage, EndMoveToSweepMessage, MoveToSweepMessage } from "../message/sweeps.messge"
import chunkEnum, { chunkType } from "../enum/chunk.enum"
import { meshTrimsLength } from "../constant/shader.const"
import textureEnum from "../enum/texture.enum"
import viewmodeEnum from "../enum/viewmode.enum"
import { httpPriority } from "../enum/http.enum"

export default class ModelMeshModule extends Module {
  colorOverlay: any
  toggleMeshOverlayColor: (e: any) => void
  modelMesh: any
  meshTrimAdded: (e: any) => void
  meshTrimRemoved: (e: any) => void
  meshTrimUniforms: any
  updateMaxQuality: (v: any) => void
  modelTextureLoader: any
  config: any
  meshData: any
  viewmodeData: any
  engine: any
  market: any
  appData: any
  sweepData: any
  panoRenderer: any
  chunkVisibiltyChecker: ChunkVisibilityChecker
  renderer: ModelRenderer
  meshTrimData: any
  constructor() {
    super(...arguments),
      (this.name = "model-mesh"),
      (this.colorOverlay = null),
      (this.toggleMeshOverlayColor = e => {
        this.colorOverlay || (this.colorOverlay = new MeshOverlayColor(() => this.modelMesh.chunks)), this.colorOverlay.toggleEnabled(e)
      }),
      (this.meshTrimAdded = e => {
        e.onPropertyChanged("enabled", () => this.updateMeshTrim(e)), this.setTrimsForFloor(e.floorIndex)
      }),
      (this.meshTrimRemoved = e => {
        e.removeOnPropertyChanged("enabled", () => this.updateMeshTrim(e)), this.setTrimsForFloor(e.floorIndex)
      }),
      (this.updateMeshTrim = e => {
        const t = this.meshTrimUniforms.setMeshTrim(e)
        this.modelMesh.chunks.forEach(s => {
          s.meshGroup === e.floorIndex && s.setMaterialsUniform(t)
        })
      }),
      (this.updateMaxQuality = (() => {
        let e, t, s
        return ({ modeChange: r, criticalChange: i, interactionChange: a }) => {
          void 0 !== i && (t = i), void 0 !== r && (e = r), void 0 !== a && (s = a)
          const o = s === deviceList.VrOrientOnly || s === deviceList.VrWithController || s === deviceList.VrWithTrackedController,
            n =
              this.modelTextureLoader.textureCount <= this.config.textureLODThreshold
                ? Math.max(chunkEnum.ULTRA, this.config.maxQuality)
                : chunkUtil.canUseID(chunkUtil.getMinQuality(chunkType.DAM, lodEnum.Standard), chunkType.DAM, lodEnum.Standard),
            h = Math.max(n, e === viewmodeEnum.Panorama && 0 === this.meshData.meshTextureOpacity.value ? n : this.config.maxQuality)
          this.modelMesh.setTextureQuality(this.modelTextureLoader, n, h)
          const d = this.viewmodeData.currentMode !== viewmodeEnum.Dollhouse && this.viewmodeData.currentMode !== viewmodeEnum.Floorplan,
            u = this.viewmodeData.transition.active && isPanOrMesh(this.viewmodeData.transition.to)
          this.modelTextureLoader.autoLoadTiles = !(o || u || (t && d)) && this.config.textureLOD !== textureEnum.NONE
        }
      })())
  }
  updateMeshTrim: any
  async init(e, t) {
    I ||
      ((THREE.Mesh.prototype.raycast = MeshUtil.raycast),
      (THREE.BufferGeometry.prototype["computeBoundsTree"] = MeshUtil.computeBoundsTree),
      (THREE.BufferGeometry.prototype["disposeBoundsTree"] = MeshUtil.disposeBoundsTree),
      (I = !0)),
      (this.config = e)
    this.engine = t
    this.market = t.market
    const [r, h, l, u, f, y, x, w, S, b, v] = await Promise.all([
      t.getModuleBySymbol(SymbolList.WEBGL_RENDERER),
      t.getModule(RaycasterModule),
      t.getModule(ModelDataModule),
      t.market.waitForData(ModelData),
      t.getModuleBySymbol(SymbolList.INPUT),
      t.getModule(RenderToTextureModule),
      t.market.waitForData(CameraData),
      t.market.waitForData(ViewmodeData),
      t.market.waitForData(SweepData),
      t.getModuleBySymbol(SymbolList.SWEEP_PANO),
      t.getModule(SettingsModule)
    ])
    this.appData = await t.market.waitForData(ApplicationData)
    this.sweepData = S
    this.viewmodeData = w
    const C = r.getScene(),
      O = l.getSignedUrls(),
      _ = u.model.uuid,
      z = t.claimRenderLayer(this.name)
    this.panoRenderer = b.getRenderer()
    const U = new RoomMeshData()
    this.chunkVisibiltyChecker = new ChunkVisibilityChecker(C, h.picking, this.engine.commandBinder.issueCommand)
    const E = v.tryGetProperty(configConst.tiledKey, !1) ? ModelMeshTiled : ModelMeshDam
    this.modelMesh = await E.createModelMesh({
      uuid: _,
      urls: O,
      renderLayer: z,
      engine: t,
      settings: configConst.switchConfig,
      roomMeshData: U,
      chunkFactory: (e, t, s, r) => new Chunk(e, t, s, r),
      chunkVisibilityChecker: this.chunkVisibiltyChecker
    })
    this.engine.market.register(this, RoomMeshData, U)
    let A = Promise.resolve()
    const V = this.modelMesh
    this.setupMarketData(V.chunks, S),
      e.renderMeshGeometry &&
        (this.modelTextureLoader = new MeshTextureLoader(e.textureLOD, O, this.modelMesh, C.camera, x, r.cwfRenderer, y, t, this.chunkVisibiltyChecker, _))
    this.modelTextureLoader.autoLoadTiles = e.textureLOD !== textureEnum.NONE
    A = this.modelMesh.initTextureLoader(
      this.modelTextureLoader,
      u.model,
      () => {
        this.updateMaxQuality({})
      },
      {
        streamingTextures: e.textureLOD !== textureEnum.NONE,
        maxQuality: e.maxQuality
      }
    )
    this.bindAppEventsToTextureQuality()
    h.setupOctree(this.modelMesh.boundingBox)
    this.modelMesh.registerCollision(f)
    e.renderMeshGeometry &&
      ((this.renderer = new ModelRenderer(C.scene, this.modelMesh, this.modelMesh, this.panoRenderer, this.meshData, this.sweepData, this.appData, e)),
      await t.addComponent(this, this.renderer),
      await A),
      this.bindings.push(
        this.engine.subscribe(PanoRenderTargetResizedMessage, e => {
          this.renderer.updateExistingTexture(e.sweepId, e.renderTarget.texture)
        })
      ),
      this.bindings.push(
        t.commandBinder.addBinding(ToggleMeshOverlayColorCommand, async e => this.toggleMeshOverlayColor(e.enabled)),
        t.commandBinder.addBinding(MeshPreviewSetPositonCommand, this.setPreviewPosition.bind(this))
      ),
      e.meshTrimEnabled ? await this.bindMeshTrimListeners() : this.bindMeshTrimListeners()
  }
  onUpdate(e) {
    this.modelMesh.onUpdate(),
      this.modelTextureLoader && !configConst.switchConfig.debugPauseTexStream && this.modelTextureLoader.update(e),
      this.chunkVisibiltyChecker && this.chunkVisibiltyChecker.update(),
      this.meshData.meshTextureOpacity.active &&
        (this.meshData.meshTextureOpacity.updateProgress(this.viewmodeData.transition.progress), this.meshData.commit())
    const t = performance.now() / 1e3
    for (const e of this.modelMesh.chunks) e.setTime(t)
  }
  setupMarketData(e, t) {
    const s = new Map(),
      r = new Map(),
      i = new THREE.Box3()
    e.forEach(e => {
      e.geometry.boundingBox && i.union(e.geometry.boundingBox),
        s.set(e.meshGroup, (s.get(e.meshGroup) || []).concat(e)),
        r.set(e.meshSubgroup, (r.get(e.meshSubgroup) || []).concat(e))
    })
    const a = new THREE.Box3()
    t.iterate(e => {
      e.isUnplaced() || (a.setFromCenterAndSize(e.position, Vectors.UNIT), i.union(a))
    })
    const o = new MeshData(0, [...i.min.toArray(), ...i.max.toArray()])
    for (const [e, t] of s.entries()) {
      const s = new THREE.Box3()
      t.forEach(e => {
        e.geometry.boundingBox && s.union(e.geometry.boundingBox)
      })
      o.meshGroups.floors.add({
        meshGroup: e,
        boundingBox: s
      })
      const i = [...new Set(t.map(e => e.meshSubgroup))].sort((e: any, t: any) => t - e).map((t: any) => ({ meshGroup: e, meshSubgroup: t }))
      o.meshGroups.roomsByFloor.set(e, i)
      for (const t of i) {
        const { meshSubgroup: s } = t
        const i = new THREE.Box3()
        ;(r.get(s) || []).forEach(e => {
          e.geometry.boundingBox && i.union(e.geometry.boundingBox)
        })
        const a = { meshGroup: s, boundingBox: i, parentMeshGroup: e }
        o.meshGroups.rooms.get(e, s) && this.log.warn("Duplicate room meshSubgroup found in model - \nold:", o.meshGroups.rooms.get(e, s), "\nnew:", a),
          o.meshGroups.rooms.set(e, s, a),
          o.meshGroupVisuals.roomFadeDist.set(e, s, 0)
      }
      o.meshGroupVisuals.floorOpacity.set(e, 1)
    }
    ;(this.meshData = o), this.meshData.onMeshIdsUpdated(this.onMeshIdsUpdated.bind(this)), this.market.register(this, MeshData, this.meshData)
  }
  onMeshIdsUpdated() {
    const e = this.meshData.meshGroups
    Object.keys(e.floorIds).length && Object.keys(e.roomIds).length && this.modelMesh.onMeshIdsUpdated(this.meshData.meshGroups)
  }
  startOpacityTransition() {
    const e = this.viewmodeData.transition.to,
      t = this.meshData.meshTextureOpacity.value,
      s = e === viewmodeEnum.Panorama ? 0 : 1,
      r = e === viewmodeEnum.Panorama ? O.Q9 : O.w2
    this.meshData.meshTextureOpacity.value !== s && this.meshData.meshTextureOpacity.modifyAnimation(t, s, 1, r)
  }
  setMeshOpacity(e) {
    e !== this.meshData.meshTextureOpacity.value && (this.meshData.meshTextureOpacity.modifyAnimation(e, e, 0), this.meshData.commit())
  }
  async bindMeshTrimListeners() {
    ;(this.meshTrimData = await this.engine.market.waitForData(MeshTrimData)), (this.meshTrimUniforms = new MeshTrimUniforms())
    const { meshTrimsByFloorIndex: e } = this.meshTrimData
    e.keys.forEach(t => {
      const s = e.get(t)
      this.bindings.push(
        s.onElementChanged({
          onAdded: this.meshTrimAdded,
          onRemoved: this.meshTrimRemoved
        })
      ),
        s.forEach(e => {
          e.onPropertyChanged("enabled", () => this.updateMeshTrim(e))
        }),
        this.setTrimsForFloor(t)
    })
  }
  setTrimsForFloor(e) {
    const t = `${e}`,
      s = this.meshTrimData.getTrimsForFloor(t),
      r = this.meshTrimUniforms.updateMeshTrimArrays(t, s)
    this.modelMesh.chunks.forEach(e => {
      ;`${e.meshGroup}` === t && e.setMaterialsUniform(r)
    })
  }
  bindAppEventsToTextureQuality() {
    let e = 0
    this.bindings.push(
      this.appData.onPropertyChanged("phase", () => this.updateMaxQuality({})),
      this.meshData.onChanged(t => {
        t.meshTextureOpacity !== e && this.updateMaxQuality({}), (e = t.meshTextureOpacity)
      }),
      this.engine.subscribe(BeginSwitchViewmodeMessage, e => {
        this.startOpacityTransition(),
          this.updateMaxQuality({
            criticalChange: !0,
            modeChange: e.toMode
          })
      }),
      this.engine.subscribe(EndSwitchViewmodeMessage, e => {
        this.updateMaxQuality({
          criticalChange: !1,
          modeChange: e.toMode
        })
      }),
      this.engine.subscribe(TourStartedMessage, () => {
        this.updateMaxQuality({ criticalChange: !0 })
      }),
      this.engine.subscribe(TourStoppedMessage, () => {
        this.updateMaxQuality({ criticalChange: !1 })
      }),
      this.engine.subscribe(BeginMoveToSweepMessage, () => {
        this.updateMaxQuality({ criticalChange: !0 })
      }),
      this.engine.subscribe(MoveToSweepMessage, e => {
        this.sweepData.getSweep(e.toSweep).isAligned() || this.setMeshOpacity(0)
      }),
      this.engine.subscribe(EndMoveToSweepMessage, () => {
        this.updateMaxQuality({ criticalChange: !1 })
      }),
      this.engine.subscribe(InteractionModeChangeMessage, e => {
        this.updateMaxQuality({ interactionChange: e.mode })
      })
    )
  }
  async setPreviewPosition(e) {
    const t = e.enabled && e.previewCirclePosition ? e.previewCirclePosition : null,
      s = e.size ? e.size : 0.3
    for (const e of this.modelMesh.chunks) e.setMeshPreviewSphere(t, s)
  }
}
